/*
 * Copyright (c) 2002-2004, xRhino, Inc.
 *
 * This library is free software; you can redistribute and/or modify
 * it under the terms of the dual license distributed with this source
 * package (a combined Trolltech QPL/GPL-compatible license)
 *
 * Under this dual license scheme, a separate license is available for use of 
 * this code with a proprietary (closed) system. For more information on the 
 * license, please see the LICENSE file distributed with this source package.
 */
#include "SugPathElement.h"

unsigned long SugPathElement::getPathLength()
{
   //READ ME: Fill this in when you figure out how to do paths
   return 0;
}

double SugPathElement::getTotalLength()
{
   //READ ME: Fill this in when you figure out how to do paths
   return 0.0;
}

SugPoint* SugPathElement::getPointAtLength(SugRealType distance)
{
   //READ ME: Fill this in when you figure out how to do paths
   return NULL;
}

unsigned long SugPathElement::getPathSegAtLength(SugRealType distance)
{
   //READ ME: Fill this in when you figure out how to do paths
   return 0;
}

vector<SugPathSeg*>* SugPathElement::getPathSegList()
{
   //READ ME: Fill this in when you figure out how to do paths
   return &mPathSegList;
}

vector<SugPathSeg*>* SugPathElement::setPathSegList(vector<SugPathSeg*>* newPathSegList)
{
   //READ ME: Fill this in when you figure out how to do paths
   //mPathSegList = newPathSegList;
   return &mPathSegList;
}

SugPathSeg* SugPathElement::createSugPathSetClosePath()
{
   SugPathSeg* newSugPathSeg = new SugPathSeg();
   newSugPathSeg->setPathSegType(PATHSEG_CLOSEPATH);
   return newSugPathSeg;
}

SugPathSeg* SugPathElement::createSugPathSegMovetoAbs(SugRealType newX, SugRealType newY)
{
   SugPathSeg* newSugPathSeg = new SugPathSeg();
   newSugPathSeg->setPathSegType(PATHSEG_MOVETO_ABS);
   newSugPathSeg->setX(newX);
   newSugPathSeg->setY(newY);
   return newSugPathSeg;
}

SugPathSeg* SugPathElement::createSugPathSegMovetoRel(SugRealType newX, SugRealType newY)
{
   SugPathSeg* newSugPathSeg = new SugPathSeg();
   newSugPathSeg->setPathSegType(PATHSEG_MOVETO_REL);
   newSugPathSeg->setX(newX);
   newSugPathSeg->setY(newY);
   return newSugPathSeg;
}

SugPathSeg* SugPathElement::createSugPathSegLinetoAbs(SugRealType newX, SugRealType newY)
{
   SugPathSeg* newSugPathSeg = new SugPathSeg();
   newSugPathSeg->setPathSegType(PATHSEG_LINETO_ABS);
   newSugPathSeg->setX(newX);
   newSugPathSeg->setY(newY);
   return newSugPathSeg;
}

SugPathSeg* SugPathElement::createSugPathSegLinetoRel(SugRealType newX, SugRealType newY)
{
   SugPathSeg* newSugPathSeg = new SugPathSeg();
   newSugPathSeg->setPathSegType(PATHSEG_LINETO_REL);
   newSugPathSeg->setX(newX);
   newSugPathSeg->setY(newY);
   return newSugPathSeg;
}

SugPathSegCurvetoCubic* SugPathElement::createSugPathSegCurvetoCubicAbs(
   SugRealType newX, SugRealType newY,
   SugRealType newX1, SugRealType newY1,
   SugRealType newX2, SugRealType newY2)
{
   SugPathSegCurvetoCubic* newSugPathSegCurvetoCubic = new SugPathSegCurvetoCubic();
   newSugPathSegCurvetoCubic->setPathSegType(PATHSEG_CURVETO_CUBIC_ABS);
   newSugPathSegCurvetoCubic->setX(newX2);
   newSugPathSegCurvetoCubic->setY(newY2);
   newSugPathSegCurvetoCubic->setX1(newX);
   newSugPathSegCurvetoCubic->setY1(newY);
   newSugPathSegCurvetoCubic->setX2(newX1);
   newSugPathSegCurvetoCubic->setY2(newY1);
   return newSugPathSegCurvetoCubic;
}

SugPathSegCurvetoCubic* SugPathElement::createSugPathSegCurvetoCubicRel(SugRealType newX, SugRealType newY, SugRealType newX1, SugRealType newY1, SugRealType newX2, SugRealType newY2)
{
   SugPathSegCurvetoCubic* newSugPathSegCurvetoCubic = new SugPathSegCurvetoCubic();
   newSugPathSegCurvetoCubic->setPathSegType(PATHSEG_CURVETO_CUBIC_REL);
   newSugPathSegCurvetoCubic->setX(newX2);
   newSugPathSegCurvetoCubic->setY(newY2);
   newSugPathSegCurvetoCubic->setX1(newX);
   newSugPathSegCurvetoCubic->setY1(newY);
   newSugPathSegCurvetoCubic->setX2(newX1);
   newSugPathSegCurvetoCubic->setY2(newY1);
   return newSugPathSegCurvetoCubic;
}

SugPathSegCurvetoQuadratic* SugPathElement::createSugPathSegCurvetoQuadraticAbs(SugRealType newX, SugRealType newY, SugRealType newX1, SugRealType newY1)
{
   SugPathSegCurvetoQuadratic* newSugPathSegCurvetoQuadratic = new SugPathSegCurvetoQuadratic();
   newSugPathSegCurvetoQuadratic->setPathSegType(PATHSEG_CURVETO_QUADRATIC_ABS);
   newSugPathSegCurvetoQuadratic->setX(newX);
   newSugPathSegCurvetoQuadratic->setY(newY);
   newSugPathSegCurvetoQuadratic->setX1(newX1);
   newSugPathSegCurvetoQuadratic->setY1(newY1);
   return newSugPathSegCurvetoQuadratic;
}

SugPathSegCurvetoQuadratic* SugPathElement::createSugPathSegCurvetoQuadraticRel(SugRealType newX, SugRealType newY, SugRealType newX1, SugRealType newY1)
{
   SugPathSegCurvetoQuadratic* newSugPathSegCurvetoQuadratic = new SugPathSegCurvetoQuadratic();
   newSugPathSegCurvetoQuadratic->setPathSegType(PATHSEG_CURVETO_QUADRATIC_REL);
   newSugPathSegCurvetoQuadratic->setX(newX);
   newSugPathSegCurvetoQuadratic->setY(newY);
   newSugPathSegCurvetoQuadratic->setX1(newX1);
   newSugPathSegCurvetoQuadratic->setY1(newY1);
   return newSugPathSegCurvetoQuadratic;
}

SugPathSegArc* SugPathElement::createSugPathSegArcAbs(SugRealType newX, SugRealType newY, SugRealType newR1, SugRealType newR2, SugRealType newAngle, bool newLargeArcFlag, bool newSweepFlag)
{
   SugPathSegArc* newSugPathSegArc = new SugPathSegArc();
   newSugPathSegArc->setPathSegType(PATHSEG_ARC_ABS);
   newSugPathSegArc->setX(newX);
   newSugPathSegArc->setY(newY);
   newSugPathSegArc->setR1(newR1);
   newSugPathSegArc->setR2(newR2);
   newSugPathSegArc->setAngle(newAngle);
   newSugPathSegArc->setLargeArcFlag(newLargeArcFlag);
   newSugPathSegArc->setSweepFlag(newSweepFlag);
   return newSugPathSegArc;
}

SugPathSegArc* SugPathElement::createSugPathSegArcRel(double newX, SugRealType newY, SugRealType newR1, SugRealType newR2, SugRealType newAngle, bool newLargeArcFlag, bool newSweepFlag)
{
   SugPathSegArc* newSugPathSegArc = new SugPathSegArc();
   newSugPathSegArc->setPathSegType(PATHSEG_ARC_REL);
   newSugPathSegArc->setX(newX);
   newSugPathSegArc->setY(newY);
   newSugPathSegArc->setR1(newR1);
   newSugPathSegArc->setR2(newR2);
   newSugPathSegArc->setAngle(newAngle);
   newSugPathSegArc->setLargeArcFlag(newLargeArcFlag);
   newSugPathSegArc->setSweepFlag(newSweepFlag);
   return newSugPathSegArc;
}

SugPathSeg* SugPathElement::createSugPathSegLinetoHorizontalAbs(SugRealType newX)
{
   SugPathSeg* newSugPathSeg = new SugPathSeg();
   newSugPathSeg->setPathSegType(PATHSEG_LINETO_HORIZONTAL_ABS);
   newSugPathSeg->setX(newX);
   return newSugPathSeg;
}

SugPathSeg* SugPathElement::createSugPathSegLinetoHorizontalRel(SugRealType newX)
{
   SugPathSeg* newSugPathSeg = new SugPathSeg();
   newSugPathSeg->setPathSegType(PATHSEG_LINETO_HORIZONTAL_REL);
   newSugPathSeg->setX(newX);
   return newSugPathSeg;
}

SugPathSeg* SugPathElement::createSugPathSegLinetoVerticalAbs(SugRealType newY)
{
   SugPathSeg* newSugPathSeg = new SugPathSeg();
   newSugPathSeg->setPathSegType(PATHSEG_LINETO_VERTICAL_ABS);
   newSugPathSeg->setY(newY);
   return newSugPathSeg;
}

SugPathSeg* SugPathElement::createSugPathSegLinetoVerticalRel(SugRealType newY)
{
   SugPathSeg* newSugPathSeg = new SugPathSeg();
   newSugPathSeg->setPathSegType(PATHSEG_LINETO_VERTICAL_REL);
   newSugPathSeg->setY(newY);
   return newSugPathSeg;
}

SugPathSegCurvetoCubicSmooth* SugPathElement::createSugPathSegCurvetoCubicSmoothAbs(SugRealType newX, SugRealType newY, SugRealType newX2, SugRealType newY2)
{
   SugPathSegCurvetoCubicSmooth* newSugPathSegCurvetoCubicSmooth = new SugPathSegCurvetoCubicSmooth();
   newSugPathSegCurvetoCubicSmooth->setPathSegType(PATHSEG_CURVETO_CUBIC_SMOOTH_ABS);
   newSugPathSegCurvetoCubicSmooth->setX2(newX);
   newSugPathSegCurvetoCubicSmooth->setY2(newY);
   newSugPathSegCurvetoCubicSmooth->setX(newX2);
   newSugPathSegCurvetoCubicSmooth->setY(newY2);
   return newSugPathSegCurvetoCubicSmooth;
}

SugPathSegCurvetoCubicSmooth* SugPathElement::createSugPathSegCurvetoCubicSmoothRel(SugRealType newX, SugRealType newY, SugRealType newX2, SugRealType newY2)
{
   SugPathSegCurvetoCubicSmooth* newSugPathSegCurvetoCubicSmooth = new SugPathSegCurvetoCubicSmooth();
   newSugPathSegCurvetoCubicSmooth->setPathSegType(PATHSEG_CURVETO_CUBIC_SMOOTH_REL);
   newSugPathSegCurvetoCubicSmooth->setX2(newX);
   newSugPathSegCurvetoCubicSmooth->setY2(newY);
   newSugPathSegCurvetoCubicSmooth->setX(newX2);
   newSugPathSegCurvetoCubicSmooth->setY(newY2);
   return newSugPathSegCurvetoCubicSmooth;
}

SugPathSeg* SugPathElement::createSugPathSegCurvetoQuadraticSmoothAbs(SugRealType newX, SugRealType newY)
{
   SugPathSeg* newSugPathSeg = new SugPathSeg();
   newSugPathSeg->setPathSegType(PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS);
   newSugPathSeg->setX(newX);
   newSugPathSeg->setY(newY);
   return newSugPathSeg;
}

SugPathSeg* SugPathElement::createSugPathSegCurvetoQuadraticSmoothRel(SugRealType newX, SugRealType newY)
{
   SugPathSeg* newSugPathSeg = new SugPathSeg();
   newSugPathSeg->setPathSegType(PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL);
   newSugPathSeg->setX(newX);
   newSugPathSeg->setY(newY);
   return newSugPathSeg;
}

char*  SugPathElement::getPathCommandToken(char** str, char* tok)
{
   int index;
   
   if (**str)
   {
      // Strip white space and commas
      while (**str == ',' ||
             **str == ' ')
         (*str)++;

      // If it is a number
      if ((**str >= '0' &&
           **str <= '9') ||
          **str == '-' ||
          **str == '.')
      {
         index = 0;

         // Add minus sign if a negative number
         if (**str == '-')
         {
            tok[index] = '-';
            index++;
            (*str)++;
         }

         // Add all digits until we run out of digits
         while ((**str >= '0' &&
                 **str <= '9') ||
                **str == '.')
         {
            tok[index] = **str;
            (*str)++;
            index++;
         }
         tok[index] = '\0';
      }
      else
      {
         // Commands are only one character
         tok[0] = **str;
         tok[1] = '\0';
         (*str)++;
      }
   }
   else
   {
      tok[0] = '\0';
   }
   return tok;
}

bool SugPathElement::getPathCommandsAttribute(char* attrName,
                                              vector<SugPathSeg*>& attrValue)
{
   char* s;
   char* sStart;
   char tok[40];
   const char* attrStr;
   int currCommand;
   float x, y;
   float c1x, c1y, c2x, c2y;
   SugPathSeg* pathSeg;

  
   attrStr = getStringAttribute(attrName);
   if (attrStr)
   {
      s = new char[strlen(attrStr) + 1];
      sStart = s;
      strcpy(s, attrStr);

      currCommand = PATHSEG_UNKNOWN;
      do
      {
         getPathCommandToken(&s, tok);
         if ((*tok >= '0' &&
              *tok <= '9') ||
             *tok == '-' ||
             *tok == '.')
         {
            pathSeg = NULL;
            
            // Token begins with a number. Should be a coordinate.
            switch (currCommand)
            {
               case PATHSEG_UNKNOWN:
                  break;

               case PATHSEG_MOVETO_ABS:
                  x = atof(tok);
                  getPathCommandToken(&s, tok);
                  y = atof(tok);
                 
                  pathSeg = createSugPathSegMovetoAbs(x, y);
                  break;

               case PATHSEG_MOVETO_REL:
                  x = atof(tok);
                  getPathCommandToken(&s, tok);
                  y = atof(tok);

                  pathSeg = createSugPathSegMovetoRel(x, y);
                  break;
                  
               case PATHSEG_LINETO_ABS:
                  x = atof(tok);
                  getPathCommandToken(&s, tok);
                  y = atof(tok);

                  pathSeg = createSugPathSegLinetoAbs(x, y);
                  break;

               case PATHSEG_LINETO_REL:
                  x = atof(tok);
                  getPathCommandToken(&s, tok);
                  y = atof(tok);

                  pathSeg = createSugPathSegLinetoRel(x, y);
                  break;

               case PATHSEG_LINETO_HORIZONTAL_ABS:
                  x = atof(tok);
                  pathSeg = createSugPathSegLinetoHorizontalAbs(x);
                  break;

               case PATHSEG_LINETO_HORIZONTAL_REL:
                  x = atof(tok);
                  pathSeg = createSugPathSegLinetoHorizontalRel(x);
                  break;

               case PATHSEG_LINETO_VERTICAL_ABS:
                  y = atof(tok);
                  pathSeg = createSugPathSegLinetoVerticalAbs(y);
                  break;

               case PATHSEG_LINETO_VERTICAL_REL:
                  y = atof(tok);
                  pathSeg = createSugPathSegLinetoVerticalRel(y);
                  break;

               case PATHSEG_CURVETO_CUBIC_ABS:
                  c1x = atof(tok);
                  getPathCommandToken(&s, tok);

                  c1y = atof(tok);
                  getPathCommandToken(&s, tok);

                  c2x = atof(tok);
                  getPathCommandToken(&s, tok);

                  c2y = atof(tok);
                  getPathCommandToken(&s, tok);

                  x = atof(tok);
                  getPathCommandToken(&s, tok);

                  y = atof(tok);
                  pathSeg = createSugPathSegCurvetoCubicAbs(c1x, c1y,
                                                            c2x, c2y,
                                                            x, y);
                  break;

               case PATHSEG_CURVETO_CUBIC_REL:
                  c1x = atof(tok);
                  getPathCommandToken(&s, tok);

                  c1y = atof(tok);
                  getPathCommandToken(&s, tok);

                  c2x = atof(tok);
                  getPathCommandToken(&s, tok);

                  c2y = atof(tok);
                  getPathCommandToken(&s, tok);

                  x = atof(tok);
                  getPathCommandToken(&s, tok);

                  y = atof(tok);
                  pathSeg = createSugPathSegCurvetoCubicRel(c1x, c1y,
                                                            c2x, c2y,
                                                            x, y);
                  break;

               case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
                  c1x = atof(tok);
                  getPathCommandToken(&s, tok);

                  c1y = atof(tok);
                  getPathCommandToken(&s, tok);

                  x = atof(tok);
                  getPathCommandToken(&s, tok);

                  y = atof(tok);
                  pathSeg = createSugPathSegCurvetoCubicSmoothAbs(c1x, c1y,
                                                                  x, y);
                  break;

               case PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
                  c1x = atof(tok);
                  getPathCommandToken(&s, tok);

                  c1y = atof(tok);
                  getPathCommandToken(&s, tok);

                  x = atof(tok);
                  getPathCommandToken(&s, tok);

                  y = atof(tok);
                  pathSeg = createSugPathSegCurvetoCubicSmoothRel(c1x, c1y,
                                                                  x, y);
                  break;
            }
            
            if (pathSeg)
            {
               attrValue.push_back(pathSeg);
            }
         }
         else
         {
            // Token begins without a number. Should be a command.
            switch (*tok)
            {
               case 'M': currCommand = PATHSEG_MOVETO_ABS; break;
               case 'm': currCommand = PATHSEG_MOVETO_REL; break;
               case 'L': currCommand = PATHSEG_LINETO_ABS; break;
               case 'l': currCommand = PATHSEG_LINETO_REL; break;
               case 'H': currCommand = PATHSEG_LINETO_HORIZONTAL_ABS; break;
               case 'h': currCommand = PATHSEG_LINETO_HORIZONTAL_REL; break;
               case 'V': currCommand = PATHSEG_LINETO_VERTICAL_ABS; break;
               case 'v': currCommand = PATHSEG_LINETO_VERTICAL_REL; break;
               case 'A': currCommand = PATHSEG_UNKNOWN; break;
               case 'a': currCommand = PATHSEG_UNKNOWN; break;
               case 'Q': currCommand = PATHSEG_UNKNOWN; break;
               case 'q': currCommand = PATHSEG_UNKNOWN; break;
               case 'T': currCommand = PATHSEG_UNKNOWN; break;
               case 't': currCommand = PATHSEG_UNKNOWN; break;
               case 'C': currCommand = PATHSEG_CURVETO_CUBIC_ABS; break;
               case 'c': currCommand = PATHSEG_CURVETO_CUBIC_REL; break;
               case 'S': currCommand = PATHSEG_CURVETO_CUBIC_SMOOTH_ABS; break;
               case 's': currCommand = PATHSEG_CURVETO_CUBIC_SMOOTH_REL; break;
               case 'Z':
               case 'z':
                  pathSeg = new SugPathSeg();
                  pathSeg->setPathSegType(PATHSEG_CLOSEPATH);
                  attrValue.push_back(pathSeg);
                  break;

               default:  currCommand = PATHSEG_UNKNOWN; break;
            }
         }
      }
      while (*s);
      delete sStart;
   }
   return attrStr;
}

SugPathElement::SugPathElement()
{
   setElementType(SugTypes::E_PATH);
}

SugPathElement::~SugPathElement()
{
}

